package com.service.admin.framework.configuration;

import org.apache.commons.pool2.impl.GenericObjectPoolConfig;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.boot.autoconfigure.condition.ConditionalOnBean;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.Primary;
import org.springframework.data.redis.connection.RedisPassword;
import org.springframework.data.redis.connection.RedisStandaloneConfiguration;
import org.springframework.data.redis.connection.lettuce.LettuceConnectionFactory;
import org.springframework.data.redis.connection.lettuce.LettucePoolingClientConfiguration;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.data.redis.serializer.GenericJackson2JsonRedisSerializer;
import org.springframework.data.redis.serializer.StringRedisSerializer;

import java.time.Duration;

@Configuration
public class RedisAutoConfig {

    @Bean
    @Primary
    public LettuceConnectionFactory defaultLettuceConnectionFactory(
            @Autowired @Qualifier("defaultRedisConfig") RedisStandaloneConfiguration defaultRedisConfig,
            @Autowired @Qualifier("defaultPoolConfig")  LettucePoolingClientConfiguration defaultPoolConfig) {
        LettuceConnectionFactory redisConnectionFactory = new LettuceConnectionFactory(defaultRedisConfig, defaultPoolConfig);
        redisConnectionFactory.setShareNativeConnection(false);
        return redisConnectionFactory;
    }

    @Bean("defaultRedisTemplate")
    public RedisTemplate<String, String> defaultRedisTemplate(
            @Qualifier("defaultLettuceConnectionFactory") LettuceConnectionFactory defaultLettuceConnectionFactory) {
        return buildRedisStringTemplate(defaultLettuceConnectionFactory);
    }

    private RedisTemplate<String, String> buildRedisStringTemplate(LettuceConnectionFactory lettuceConnectionFactory) {
        RedisTemplate<String, String> redisTemplate = new RedisTemplate<String, String>();
        redisTemplate.setConnectionFactory(lettuceConnectionFactory);

        //使用StringRedisSerializer来序列化和反序列化redis的key
        redisTemplate.setKeySerializer(new StringRedisSerializer());
        redisTemplate.setValueSerializer(new StringRedisSerializer());

        //使用Jackson2JsonRedisSerializer来序列化和反序列化redis的value值
        redisTemplate.setHashKeySerializer(new StringRedisSerializer());
        redisTemplate.setHashValueSerializer(new GenericJackson2JsonRedisSerializer());

        //开启事务
//        redisTemplate.setEnableTransactionSupport(true);
        redisTemplate.afterPropertiesSet();
        return redisTemplate;
    }

    //撮合引擎redis配置
    @Bean
    public LettuceConnectionFactory matchEngineLettuceConnectionFactory(
            @Autowired @Qualifier("matchEngineRedisConfig") RedisStandaloneConfiguration matchEngineRedisConfig,
            @Autowired @Qualifier("matchEnginePoolConfig") LettucePoolingClientConfiguration matchEnginePoolConfig) {
        LettuceConnectionFactory redisConnectionFactory = new LettuceConnectionFactory(matchEngineRedisConfig, matchEnginePoolConfig);
        redisConnectionFactory.setShareNativeConnection(false);
        return redisConnectionFactory;
    }

    @Bean("redisMatchEngineTemplate")
    public RedisTemplate<String, String> redisMatchEngineTemplate(
            @Qualifier("matchEngineLettuceConnectionFactory") LettuceConnectionFactory matchEngineLettuceConnectionFactory) {
        return buildRedisStringTemplate(matchEngineLettuceConnectionFactory);
    }


    @Configuration
    public static class MatchEngineRedisConfig {
        @Value("${spring.redis.host}")
        private String host;
        @Value("${spring.redis.port}")
        private Integer port;
        @Value("${spring.redis.password}")
        private String password;
        @Value("${redis.database.match-engine}")
        private Integer database;
        @Value("${spring.redis.timeout}")
        private Duration timeout;
        @Value("${spring.redis.lettuce.pool.min-idle}")
        private int minIdle;
        @Value("${spring.redis.lettuce.pool.max-idle}")
        private int maxIdle;
        @Value("${spring.redis.lettuce.pool.max-active}")
        private int maxActive;
        @Value("${spring.redis.lettuce.pool.max-wait}")
        private Duration maxWait;

        @Bean
        public LettucePoolingClientConfiguration matchEnginePoolConfig() {
            GenericObjectPoolConfig pool = new GenericObjectPoolConfig();
            pool.setMaxTotal(maxActive);
            pool.setMaxWaitMillis(maxWait.toMillis());
            pool.setMaxIdle(maxIdle);
            pool.setMinIdle(minIdle);

            return LettucePoolingClientConfiguration.builder()
                    .poolConfig(pool)
                    .commandTimeout(timeout)
                    .shutdownTimeout(timeout)
                    .build();
        }

        @Bean
        public RedisStandaloneConfiguration matchEngineRedisConfig() {
            RedisStandaloneConfiguration config = new RedisStandaloneConfiguration();
            config.setHostName(host);
            config.setPassword(RedisPassword.of(password));
            config.setPort(port);
            config.setDatabase(database);
            return config;
        }
    }


    @Configuration
    public static class DefaultRedisConfig {
        @Value("${spring.redis.host}")
        private String host;
        @Value("${spring.redis.port}")
        private Integer port;
        @Value("${spring.redis.password}")
        private String password;
        @Value("${spring.redis.database}")
        private Integer database;
        @Value("${spring.redis.timeout}")
        private Duration timeout;
        @Value("${spring.redis.lettuce.pool.min-idle}")
        private int minIdle;
        @Value("${spring.redis.lettuce.pool.max-idle}")
        private int maxIdle;
        @Value("${spring.redis.lettuce.pool.max-active}")
        private int maxActive;
        @Value("${spring.redis.lettuce.pool.max-wait}")
        private Duration maxWait;

        @Bean
        public LettucePoolingClientConfiguration defaultPoolConfig() {
            GenericObjectPoolConfig config = new GenericObjectPoolConfig();
            config.setMaxTotal(maxActive);
            config.setMaxIdle(maxIdle);
            config.setMinIdle(minIdle);
            config.setMaxWaitMillis(maxWait.toMillis());
            return LettucePoolingClientConfiguration.builder()
                    .poolConfig(config)
                    .commandTimeout(timeout)
                    .shutdownTimeout(timeout)
                    .build();
        }

        @Bean
        public RedisStandaloneConfiguration defaultRedisConfig() {
            RedisStandaloneConfiguration config = new RedisStandaloneConfiguration();
            config.setHostName(host);
            config.setPassword(RedisPassword.of(password));
            config.setPort(port);
            config.setDatabase(database);
            return config;
        }
    }


}
